package org.yunai.swjg.server.core.service;

import org.springframework.stereotype.Component;
import org.yunai.swjg.server.core.message.GameMessage;
import org.yunai.swjg.server.core.session.GameSession;
import org.yunai.yfserver.message.sys.SysInternalMessage;
import org.yunai.yfserver.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 在线信息管理
 * User: yunai
 * Date: 13-3-29
 * Time: 上午10:30
 */
@Component
public class OnlineContextService {

    /**
     * 游戏消息处理器
     */
    @Resource
    private GameMessageProcessor gameMessageProcessor;

    /**
     * 玩家集合<br />
     * <K, V>对应<PlayerEntity.id, Online>
     */
    private ConcurrentMap<Integer, Online> playerMap = new ConcurrentHashMap<Integer, Online>();
    /**
     * 会话与Online缓存集合<br />
     * <K, V>对应<会话, Online>
     */
    private ConcurrentMap<GameSession, Online> sessionMap = new ConcurrentHashMap<GameSession, Online>();
    /**
     * 用户集合<br />
     * <K, V>对应<User.id, Online>
     */
    private ConcurrentMap<Integer, Online> userMap = new ConcurrentHashMap<Integer, Online>();
//    /** [游戏中]玩家人数 */
//    private AtomicInteger onlineCount = new AtomicInteger(0);
    /**
     * 即将认证用户集合<br />
     * <K, V>对应<User.id, Online>
     */
    private ConcurrentMap<Integer, Online> willAuthUserMap = new ConcurrentHashMap<Integer, Online>();

    /**
     * 获得玩家
     *
     * @param pid 玩家编号
     * @return 玩家在线信息
     */
    public Online getPlayer(Integer pid) {
        // TODO 考虑下lock
        return playerMap.get(pid);
    }

    /**
     * 添加玩家
     *
     * @param online 玩家在线信息
     */
    public void addPlayer(Online online) {
        // TODO 考虑下lock
        playerMap.put(online.getPlayer().getId(), online);
    }

    /**
     * 移除玩家
     *
     * @param online 玩家在线信息
     */
    public void removePlayer(Online online) {
        // TODO 考虑下lock
        playerMap.remove(online.getPlayer().getId());
    }

    /**
     * @return 所有玩家集合(unmodifiableCollection)
     */
    public Collection<Online> getPlayers() {
        return Collections.unmodifiableCollection(playerMap.values());
    }

    /**
     * 添加在线信息<br />
     *
     * @param online 在线信息
     */
    public Online addOnline(Online online) {
        return sessionMap.put(online.getSession(), online);
    }

    /**
     * 移除在线信息
     *
     * @param session 会话
     */
    public Online removeOnline(GameSession session) {
        return sessionMap.remove(session);
    }

    /**
     * 获得用户
     *
     * @param uid 用户编号
     * @return 在线信息
     */
    public Online getUser(Integer uid) {
        return userMap.get(uid);
    }

    /**
     * 添加用户
     *
     * @param online 在线信息
     */
    public void addUser(Online online) {
        userMap.put(online.getUser().getId(), online);
    }

    /**
     * 移除用户
     *
     * @param online 在线信息
     */
    public void removeUser(Online online) {
        userMap.remove(online.getUser().getId());
    }

    /**
     * 添加即将认证用户
     *
     * @param online 在线信息
     */
    public void addWillAuthUser(Online online) {
        // TODO 以后在处理下WillAuthMap元素已经存在的情况
        willAuthUserMap.put(online.getUser().getId(), online);
    }

    /**
     * 移除即将认证用户
     *
     * @param uid 玩家编号
     * @return 在线信息
     */
    public Online removeWillAuthUser(Integer uid) {
        return willAuthUserMap.remove(uid);
    }

    /**
     * 给游戏状态({@link OnlineState#gaming}发送消息<br />
     * 若调用该方法的线程不是消息处理线程，则将消息转发到消息处理线程在进行广播
     *
     * @param msg 消息
     */
    public void broadcastMessage(final GameMessage msg) {
        // 当前消息线程不是消息处理线程，则将消息转发到消息处理线程进行广播
        if (!ObjectUtils.isEqual(Thread.currentThread().getId(), gameMessageProcessor.getThreadId())) {
            gameMessageProcessor.put(new SysInternalMessage() {
                @Override
                public void execute() {
                    OnlineContextService.this.broadcastMessage(msg);
                }

                @Override
                public short getCode() {
                    return 0;
                }
            });
            return;
        }
        // TODO GameUnitList 干啥的
        // 真正进行消息广播
        for (Online online : playerMap.values()) {
            if (online.getState() == OnlineState.gaming) {
                online.write(msg);
            }
        }
    }
}
